package fr.openwide.core.jpa.migration.service;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import org.apache.commons.lang3.mutable.MutableInt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import fr.openwide.core.jpa.business.generic.model.GenericEntity;
import fr.openwide.core.jpa.business.generic.service.IGenericEntityService;
import fr.openwide.core.jpa.exception.SecurityServiceException;
import fr.openwide.core.jpa.exception.ServiceException;
import fr.openwide.core.jpa.migration.rowmapper.AbstractListResultRowMapper;
import fr.openwide.core.jpa.migration.rowmapper.AbstractMapResultRowMapper;
import fr.openwide.core.jpa.migration.rowmapper.AbstractResultRowMapper;
import fr.openwide.core.jpa.migration.util.ISimpleEntityMigrationInformation;
import fr.openwide.core.jpa.more.business.generic.model.GenericListItem;
import fr.openwide.core.jpa.more.business.generic.service.IGenericListItemService;
public abstract class AbstractSimpleEntityMigrationService extends AbstractMigrationService {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractSimpleEntityMigrationService.class);
@Autowired
private IGenericListItemService genericListItemService;
private Set<Class<? extends GenericEntity<Long, ?>>> clazzSet = Sets.newLinkedHashSet();
protected <T extends GenericEntity<Long, ?>> Callable<Void> getEntityMigrationTask(MutableInt totalItems,
final ISimpleEntityMigrationInformation<T> entityInformation) {
final List<Long> entityIds = ImmutableList.copyOf(getJdbcTemplate().queryForList(entityInformation.getSqlAllIds(), Long.class));
return getEntityMigrationTask(totalItems, entityIds, entityInformation, null);
}
protected <T extends GenericEntity<Long, ?>> Callable<Void> getEntityMigrationTask(MutableInt totalItems,
final ISimpleEntityMigrationInformation<T> entityInformation,
final IGenericEntityService<Long, T> genericEntityService) {
final List<Long> entityIds = ImmutableList.copyOf(getJdbcTemplate().queryForList(entityInformation.getSqlAllIds(), Long.class));
return getEntityMigrationTask(totalItems, entityIds, entityInformation, genericEntityService);
}
protected <T extends GenericEntity<Long, ?>> Callable<Void> getEntityMigrationTask(MutableInt totalItems,
final List<Long> entityIds, final ISimpleEntityMigrationInformation<T> entityInformation,
final IGenericEntityService<Long, T> genericEntityService) {
totalItems.add(entityIds.size());
return new Callable<Void>() {
@Override
public Void call() throws Exception {
List<T> entitiesList = Lists.newArrayListWithExpectedSize(entityIds.size());
Map<Long, T> entitiesMap = Maps.newHashMapWithExpectedSize(entityIds.size());
RowMapper<?> rowMapper;
Class<? extends AbstractResultRowMapper<?>> rowMapperClass = entityInformation.getRowMapperClass();
if (AbstractMapResultRowMapper.class.isAssignableFrom(rowMapperClass)) {
rowMapper = rowMapperClass.getConstructor(Map.class).newInstance(entitiesMap);
} else if (AbstractListResultRowMapper.class.isAssignableFrom(rowMapperClass)) {
rowMapper = rowMapperClass.getConstructor(List.class).newInstance(entitiesList);
} else {
throw new IllegalStateException(String.format("Type de rowmapper non reconnu %1$s", rowMapperClass.getSimpleName()));
}
AutowireCapableBeanFactory autowire = applicationContext.getAutowireCapableBeanFactory();
autowire.autowireBean(rowMapper);
autowire.initializeBean(rowMapper, rowMapper.getClass().getSimpleName());
prepareRowMapper(rowMapper, entityIds);
if (entityInformation.getParameterIds() == null) {
getJdbcTemplate().query(entityInformation.getSqlRequest(), rowMapper);
} else {
MapSqlParameterSource entityIdsParameterSource = new MapSqlParameterSource();
entityIdsParameterSource.addValue(entityInformation.getParameterIds(), entityIds);
getNamedParameterJdbcTemplate().query(entityInformation.getSqlRequest(), entityIdsParameterSource,
rowMapper);
}
Collection<T> entities;
if (AbstractMapResultRowMapper.class.isAssignableFrom(rowMapperClass)) {
entities = entitiesMap.values();
} else if (AbstractListResultRowMapper.class.isAssignableFrom(rowMapperClass)) {
entities = entitiesList;
} else {
throw new IllegalStateException(String.format("Type de rowmapper non reconnu %1$s", rowMapperClass.getSimpleName()));
}
try {
for (T entity : entities) {
if (GenericListItem.class.isAssignableFrom(entityInformation.getEntityClass())) {
genericListItemService.create((GenericListItem<?>)entity);
} else if (genericEntityService != null) {
genericEntityService.create(entity);
} else {
entityManagerUtils.getEntityManager().persist(entity);
}
}
} catch (RuntimeException | ServiceException | SecurityServiceException e) {
LOGGER.error("Erreur lors de la persistence d'un(e) "
+ entityInformation.getEntityClass().getSimpleName()
+ ". {} créations annulées.", entities.size(), e);
}
clazzSet.add(entityInformation.getEntityClass());
return null;
}
};
}
protected void prepareRowMapper(RowMapper<?> rowMapper, List<Long> entityIds) {
}
protected <T extends GenericEntity<Long, ?>> List<Callable<Void>> getEntityMigrationTasks(final MutableInt totalItems,
final ISimpleEntityMigrationInformation<T> entityInformation) {
return getEntityMigrationTasks(totalItems, entityInformation, null);
}
protected <T extends GenericEntity<Long, ?>> List<Callable<Void>> getEntityMigrationTasks(final MutableInt totalItems,
final ISimpleEntityMigrationInformation<T> entityInformation,
final IGenericEntityService<Long, T> entityService) {
if (entityInformation.getParameterIds() == null) {
throw new IllegalStateException("ParameterIds null. Pour importer les entités par lot, il faut spécifier ParameterIds.");
}
final List<Long> entityIds = ImmutableList.copyOf(getJdbcTemplate().queryForList(entityInformation.getSqlAllIds(), Long.class));
List<List<Long>> entityIdsPartitions = Lists.partition(entityIds, 100);
List<Callable<Void>> callables = Lists.newArrayList();
for (final List<Long> entityIdsPartition : entityIdsPartitions) {
callables.add(getEntityMigrationTask(totalItems, entityIdsPartition, entityInformation, entityService));
}
clazzSet.add(entityInformation.getEntityClass());
return callables;
}
protected void updateReferentielSequences() {
for (Class<? extends GenericEntity<Long, ?>> clazz : clazzSet) {
updateSequence(clazz);
}
}
}